use ordered_float::NotNan;
#[derive(Debug, PartialEq)]
pub enum Operator {
    Add,
    Sub,
    Mul,
    Div,
}

#[derive(Debug, PartialEq,Clone)]
pub enum BoolOperator {
    And,
    Or,
    Eq,
    Less,
    Greater,
    NotEq,
    LessEq,
    GreaterEq
}

pub type Suite = Vec<Statement>;

#[derive(Debug, PartialEq)]
pub struct ArgumentList {
    pub args: Vec<Expression>
}


#[derive(Debug, PartialEq)]
pub enum Number {
    Integer(i64),
    Float(NotNan<f64>)
}
#[derive(Debug, PartialEq)]
pub enum UnOpType {
    Not
}

#[derive(Debug, PartialEq)]
pub enum Expression {
    Number(Number),
    Identifier(String),
    Binop {
        a: Box<Expression>,
        op: Operator,
        b: Box<Expression>,
    },
    BoolOp {
        a: Box<Expression>,
        op: BoolOperator,
        b: Box<Expression>,
    },
    List(Vec<Expression>),
    Call {
        function: Box<Expression>,
        args: Vec<Expression>
    },
    True,
    False,
    UnaryOp {
        a:Box<Expression>,
        op:UnOpType
    },
    IndexOp {
        value:Box<Expression>,
        idx:Box<Expression>
    }
}

#[derive(Debug, PartialEq)]
pub enum Statement {
    Let {
        sym_name:String,
        value:Expression
    },
    FunctionDef {
        name: String,
        args: Vec<String>,
        body: Suite
    },
    Expression(Expression),
    If {
        test:Expression,
        block:Suite,
        orelse: Option<Suite>
    },
    While {
        test: Expression,
        body: Suite
    },
    Return { value: Option<Expression> },
    Break,
    Continue,
    Assign {
        name:Expression,
        value:Expression
    }
}
#[derive(Debug, PartialEq)]
pub struct Program {
    pub statements: Suite,
}


/*
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Literal {
    Int(i64),
    Float(NotNan<f64>),
    Char(char),
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expr<Id = String> {
    Ident(Id),
    Literal(Literal),
    Let(String,Literal)
}*/